home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_300 / 388_01 / ae / 93 / jul / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-06-12  |  10.7 KB  |  573 lines

  1. /*
  2.  * main.c        
  3.  *
  4.  * Anthony's Editor July 93
  5.  *
  6.  * Copyright 1993, 1993 by Anthony Howe.  All rights reserved.  No warranty.
  7.  */
  8.  
  9. #include <ctype.h>
  10. #include <errno.h>
  11. #include "header.h"
  12.  
  13. static int intsig = FALSE;
  14.  
  15. #ifdef SIGINT
  16. static void
  17. sigint(sig)
  18. int sig;
  19. {
  20.     intsig = TRUE;
  21. }
  22. #endif
  23.  
  24. #ifdef ATARI_ST
  25. #include <setjmp.h>
  26.  
  27. static jmp_buf ignore;
  28. static void (*old_sigint) _((int));
  29.  
  30. static void
  31. sigint(sig)
  32. int sig;
  33. {
  34.     intsig = TRUE;
  35.     longjmp(ignore, 1);
  36. }
  37. #endif /* ATARI_ST */
  38.  
  39. int
  40. main(argc, argv)
  41. int argc;
  42. char **argv;
  43. {
  44.     int i;
  45.     t_keymap *kp;
  46.     char *ap, *config;
  47.  
  48.     /* Find basename. */
  49.     prog_name = *argv; 
  50.     i = strlen(prog_name);
  51.     while (0 <= i && prog_name[i] != '\\' && prog_name[i] != '/')
  52.         --i;
  53.     prog_name += i+1;
  54.  
  55.     /* Parse options. */
  56.     config = CONFIG;
  57.     for (--argc, ++argv; 0 < argc && **argv == '-'; --argc, ++argv) {
  58.         ap = &argv[0][1];
  59.         if (*ap == '-' && ap[1] == '\0') {
  60.             /* -- terminates options. */
  61.             --argc;
  62.             ++argv;
  63.             break;
  64.         }
  65.         while (*ap != '\0') {
  66.             switch (*ap++) {
  67.             case 'f':
  68.                 /* -f <config_file>  or -f<config_file> */
  69.  
  70.                 if (*ap != '\0') {
  71.                     config = ap;
  72.                 } else if (1 < argc) {
  73.                     config = *++argv;
  74.                     --argc;
  75.                 } else {
  76.                     fatal(f_usage);
  77.                 }
  78.                 break;
  79.             default:
  80.                 fatal(f_usage);
  81.             }
  82.             break;
  83.         }
  84.     }
  85.  
  86.     if (initscr() == NULL)
  87.         fatal(f_initscr);
  88.     if (initkey(config, &key_map) != INITKEY_OK)
  89.         fatal(f_config);
  90.  
  91.     /* Determine if editor is modeless or not.
  92.      * Define insert mode keys from the master table. 
  93.      */
  94.     for (modeless = TRUE, kp = key_map; kp->code != K_ERROR; ++kp) {
  95.         switch (kp->code) {
  96.         case K_INSERT_ENTER:
  97.             modeless = FALSE;
  98.             break;
  99.         case K_INSERT_EXIT:
  100.             kp->code = K_DISABLED;
  101.             key_mode[0].lhs = kp->lhs;
  102.             break;
  103.         case K_STTY_ERASE:
  104.             key_mode[1].lhs = kp->lhs;
  105.             break;
  106.         case K_LITERAL:
  107.             key_mode[2].lhs = kp->lhs;
  108.             break;
  109.         case K_HELP_OFF:
  110.             textline = 0;
  111.             break;
  112.         }
  113.     }
  114.  
  115.     noecho();
  116.     lineinput(FALSE);
  117.     idlok(stdscr, TRUE);
  118.  
  119.     if (0 < argc) {
  120.         (void) load(*argv);
  121.         /* Save filename irregardless of load() success. */
  122.         strcpy(filename, *argv);
  123.         modified = FALSE;
  124.     }
  125.     if (!growgap(CHUNK))
  126.         fatal(f_alloc);
  127.  
  128.     top();
  129.     i = msgflag;
  130.     help();
  131.     msgflag = i;
  132.  
  133.     /* Disable recognition of user interrupt. */
  134. #ifdef SIGQUIT
  135.     if (signal(SIGQUIT, SIG_IGN) == SIG_ERR)
  136.         fatal(f_error);
  137. #endif
  138. #ifdef SIGINT
  139.     if (signal(SIGINT, SIG_IGN) == SIG_ERR)
  140.         fatal(f_error);
  141. #endif
  142. #ifdef ATARI_ST
  143.     old_sigint = (void (*)()) Setexc(0x102, sigint);
  144.     if (setjmp(ignore) != 0)
  145.         msg(m_interrupt);
  146. #endif
  147.     while (!done) {
  148.         i = 0;
  149.         input = getkey(key_map);
  150.         while (table[i].key != 0 && input != table[i].key)
  151.             ++i;
  152.         if (table[i].func != NULL) 
  153.             (*table[i].func)();
  154.         else if (modeless)
  155.             insert();
  156.         display(table[i].disp);
  157.     }
  158.  
  159. #ifdef SIGQUIT
  160.     (void) signal(SIGQUIT, SIG_DFL);
  161. #endif
  162. #ifdef SIGINT
  163.     (void) signal(SIGINT, SIG_DFL);
  164. #else
  165. #ifdef ATARI_ST
  166.     (void) Setexc(0x102, old_sigint);
  167. #endif
  168. #ifdef __MSDOS__
  169. #endif
  170. #endif /* SIGINT */    
  171.  
  172.     if (scrap != NULL)
  173.         free(scrap);
  174.     finikey(key_map);
  175.     move(LINES-1, 0);
  176.     refresh();
  177.     endwin();
  178.     putchar('\n');
  179.     return (0);
  180.  
  181. }
  182.  
  183. #ifdef TERMIOS
  184. #include <termios.h>
  185.  
  186. /*
  187.  *    Set the desired input mode.
  188.  *
  189.  *    FALSE enables immediate character processing (disable line processing
  190.  *    and signals for INTR, QUIT, and SUSP).  TRUE enables line processing 
  191.  *    and signals (disables immediate character processing).  In either 
  192.  *    case flow control (XON/XOFF) is still active.  
  193.  *
  194.  *    If the termios function calls fail, then fall back on using 
  195.  *    CURSES' cbreak()/nocbreak() functions; however signals will be
  196.  *    still be in effect.
  197.  */
  198. void
  199. lineinput(bf)
  200. int bf;
  201. {
  202.     int error;
  203.     struct termios term;
  204.     error = tcgetattr(fileno(stdin), &term) < 0;
  205.     if (!error) {
  206.         if (bf)
  207.             term.c_lflag |= ISIG | ICANON;
  208.         else
  209.             term.c_lflag &= ~(ISIG | ICANON);
  210.         error = tcsetattr(fileno(stdin), TCSANOW, &term) < 0;
  211.     }
  212.     /* Fall back on CURSES functions that do almost what we need if
  213.      * either tcgetattr() or tcsetattr() fail.
  214.      */
  215.     if (error) {
  216.         if (bf)
  217.             nocbreak();
  218.         else
  219.             cbreak();
  220.     }
  221. }
  222. #endif /* TERMIOS */
  223.  
  224. void
  225. fatal(m)
  226. t_msg m;
  227. {
  228.     if (curscr != NULL) {
  229.         move(LINES-1, 0);
  230.         refresh();
  231.         endwin();
  232.         putchar('\n');
  233.     }
  234.     fprintf(stderr, getmsg(m), prog_name);
  235.     if (m == f_ok)
  236.         exit(0);
  237.     if (m == f_error)
  238.         exit(1);
  239.     if (m == f_usage)
  240.         exit(2);
  241.     exit(3);
  242. }
  243.  
  244. #ifdef va_dcl
  245. void
  246. msg(va_alist)
  247. va_dcl
  248. {
  249.     long num;
  250.     char *f, *m;
  251.     va_list args;
  252.  
  253.     va_start(args);
  254.     f = getmsg(va_arg(args, t_msg));
  255.     for (m = msgline; *f != '\0'; ) { 
  256.         if (*f == '%') {
  257.             switch (*++f) {
  258.             case 's':
  259.                 (void) strcpy(m, va_arg(args, char *));
  260.                 break;
  261.             case 'l':
  262.                 if (*++f != 'd') {
  263.                     (void) strcpy(m, "UNSUPPORTED");
  264.                     break;
  265.                 }
  266.                 num = va_arg(args, long);
  267.                 /* fall */
  268.             case 'd':
  269.                 if (f[-1] == '%')
  270.                     num = (long) va_arg(args, int);
  271.                 sprintf(m, "%ld", num);
  272.                 break;
  273.             }
  274.             m += strlen(m);
  275.             ++f;
  276.         } else {
  277.             *m++ = *f++;
  278.         }
  279.     }
  280.     *m = '\0';
  281.     va_end(args);
  282.     msgflag = TRUE;
  283. }
  284. #else /* not va_dcl */
  285. #ifdef __STDC__
  286. void
  287. msg(t_msg m, ...)
  288. #else
  289. void
  290. msg(m)
  291. t_msg m;
  292. #endif /* __STDC__ */
  293. {
  294.     va_list args;
  295.     va_start(args, m);
  296.     (void) vsprintf(msgline, getmsg(m), args);
  297.     va_end(args);
  298.     msgflag = TRUE;
  299. }
  300. #endif /* va_dcl */
  301.  
  302. /*
  303.  * Return a pointer to a message.
  304.  * Messages have the format "number:text", where
  305.  * number is an index into a message table and text
  306.  * is the default text if no message defined.
  307.  */
  308. char *
  309. getmsg(m)
  310. t_msg m;
  311. {
  312.     char *text;
  313.     long index;
  314.  
  315.     index = strtol(m, &text, 0);
  316.     if (0 <= index && message[index] != NULL)
  317.         return (message[index]);
  318.     return (text+1);
  319. }
  320.  
  321. /*
  322.  *    Convert a string to lower case.  Return the string pointer.
  323.  */
  324. char *
  325. strlwr(str)
  326. char *str;
  327. {
  328.     register char *s;
  329.     for (s = str; *s != '\0'; ++s)
  330.         if (isupper(*s))
  331.             *s = tolower(*s);
  332.     return (str);
  333. }
  334.  
  335. /*
  336.  *    Make a duplicate of a string.  Return a pointer to an allocated
  337.  *    copy of the string, or NULL if malloc() failed.
  338.  */
  339. char *
  340. strdup(str)
  341. const char *str;
  342. {
  343.     char *new;
  344.     if ((new = (char*) malloc(strlen(str)+1)) != NULL)
  345.         (void) strcpy(new, str);
  346.     return (new);
  347. }    
  348.  
  349. /*
  350.  * Replace old with new characters.  If method
  351.  *    negative    Nth occurence from the end;
  352.  *    0        all occurences;
  353.  *    positive    Nth occurence from the beginning.
  354.  */
  355. char *
  356. strrep(str, old, new, method)
  357. char *str;
  358. int old, new, method;
  359. {
  360.     register char *ptr = str;
  361.     register int direction = 1;
  362.  
  363.     if (method == 0) {
  364.         /* All occurences. */
  365.         for (; *ptr != '\0'; ++ptr)
  366.             if (*ptr == old)
  367.                 *ptr = new;
  368.         return (str);
  369.     } else if (method < 0) {
  370.         /* Start from the end going backwards. */
  371.         direction = -1;
  372.         ptr = &str[strlen(str)] - 1;
  373.         method = -method;
  374.     }
  375.  
  376.     /* Change the Nth occurence. */
  377.     for (; *ptr != '\0'; ptr += direction) {
  378.         if (*ptr == old && --method <= 0) {
  379.             *ptr = new;
  380.             break;
  381.         }
  382.     }
  383.  
  384.     return (str);
  385. }
  386.  
  387. /*
  388.  *
  389.  */
  390. char *
  391. pathname(path, file)
  392. char *path, *file;
  393. {
  394.     char *buf;
  395.     size_t plen, flen;
  396.  
  397.     plen = path == NULL ? 0 : strlen(path);
  398.     flen = file == NULL ? 0 : strlen(file);
  399.     buf = (char*) malloc(plen + flen + 2);
  400.     if (buf == NULL)
  401.         return (NULL);
  402.     (void) strcpy(buf, path);
  403.     buf[plen] = '/';
  404.     (void) strcpy(&buf[plen+1], file);
  405.     return (buf);
  406. }
  407.  
  408. /*
  409.  * Open resource file.
  410.  * Search order is: abs, ./rel, $HOME/rel, $ETCDIR/rel
  411.  */
  412. FILE *
  413. openrc(fn)
  414. char *fn;
  415. {
  416.     FILE *fp;
  417.     char *ptr, *buf;
  418.  
  419.     if ((fp = fopen(fn, "r")) != NULL)
  420.         return (fp);
  421.  
  422.     if ((ptr = getenv("HOME")) != NULL 
  423.     && (buf = pathname(ptr, fn)) != NULL) {
  424.         fp = fopen(buf, "r");
  425. #ifdef EITHER_SLASH
  426.         if (fp == NULL)
  427.             fp = fopen(strrep(buf, '/', '\\', 0), "r");
  428. #endif /* EITHER_SLASH */
  429.         free(buf);
  430.         if (fp != NULL)
  431.             return (fp);
  432.     }
  433.  
  434.     if ((ptr = getenv("ETCDIR")) != NULL 
  435.     && (buf = pathname(ptr, fn)) != NULL) {
  436.         fp = fopen(buf, "r");
  437. #ifdef EITHER_SLASH
  438.         if (fp == NULL)
  439.             fp = fopen(strrep(buf, '/', '\\', 0), "r");
  440. #endif /* EITHER_SLASH */
  441.         free(buf);
  442.         if (fp != NULL)
  443.             return (fp);
  444.     }
  445.  
  446.     return (NULL);
  447. }
  448.  
  449. /*
  450.  * Get an arbitrarily long line of text from a file.
  451.  * The read is terminated when an unescaped newline is found.
  452.  * The buffer that is passed back in ptr will be '\0' terminated.  
  453.  * If an error occurs, the contents of ptr will be undefined.
  454.  */
  455. long
  456. getblock(fp, ptr)
  457. FILE *fp;
  458. char **ptr;
  459. {
  460.     int ch, escape;
  461.     char *buf, *new;
  462.     size_t blen, len = 0;
  463.  
  464.     *ptr = NULL;
  465.     if ((buf = (char *) malloc(blen = BUFSIZ)) == NULL)
  466.         return (GETBLOCK_ALLOC);
  467.  
  468.     escape = FALSE;
  469.     while ((ch = fgetc(fp)) != EOF) {
  470.         buf[len++] = ch;
  471.  
  472.         if (ch == '\n') {
  473.             if (escape) {
  474.                 len -= 2;
  475.                 escape = FALSE;
  476.                 continue;
  477.             }
  478.             buf[len] = '\0';
  479.             break;
  480.         }
  481.         escape = !escape && ch == '\\'; 
  482.             
  483.         if (blen <= len) {
  484.             blen += BUFSIZ;
  485.             if ((new = (char*) realloc(buf, blen)) == NULL) {
  486.                 free(buf);
  487.                 return (GETBLOCK_ALLOC);
  488.             }
  489.             buf = new;
  490.         }
  491.     }
  492.  
  493.     if (ferror(fp)) {
  494.         free(buf);
  495.         return (GETBLOCK_ERROR);
  496.     }
  497.     if (feof(fp)) {
  498.         free(buf);
  499.         return (GETBLOCK_EOF);
  500.     } 
  501.  
  502.     buf[len++] = '\0';
  503.  
  504.     /* Shrink buffer to exact size required for the string. */
  505.     if ((new = (char *) realloc(buf, len)) == NULL)
  506.         new = buf;
  507.     *ptr = new;
  508.     return (len);
  509. }
  510.  
  511. /*
  512.  * Encode in-place the given buffer.
  513.  * Return the new length of encoded buffer or -1 for an error.
  514.  */
  515. long
  516. encode(buf)
  517. char *buf;
  518. {
  519.     unsigned long number;
  520.     char *store, *fetch, *ctrl;
  521.     static char escmap[] = "bfnrst";
  522.     static char escvalue[] = "\b\f\n\r \t";
  523.     static char control[] = "@abcdefghijklmnopqrstuvwxyz[\\]^_";
  524.  
  525.     for (store = fetch = buf; *fetch != '\0'; ++store) {
  526.         switch (*fetch) {
  527.         case '^':
  528.             ++fetch;
  529.             if (*fetch == '?') {
  530.                 /* ^? equals ASCII DEL character. */ 
  531.                 *store = 0x7f;
  532.             } else {
  533.                 /* Non-ASCII dependant control key mapping. */
  534.                 if (isupper(*fetch))
  535.                     *fetch = tolower(*fetch);
  536.                 if ((ctrl = strchr(control, *fetch)) == NULL)
  537.                     /* Not a control key mapping. */
  538.                     return (-1);
  539.                 *store = (char) (ctrl - control);    
  540.             }
  541.             ++fetch;
  542.             break;
  543.         case '\\':
  544.             /* Escapes. */
  545.             ++fetch;
  546.             if (isdigit(*fetch)) {
  547.                 /* Numeric escapes allow for
  548.                  *  octal    \0nnn
  549.                  *  hex        \0xnn
  550.                  *  decimal    \nnn 
  551.                  */
  552.                 number = strtol(fetch, &fetch, 0);
  553.                 if (number < 0 || 255 < number)
  554.                     /* Number not in range 0..255. */
  555.                     return (-1);
  556.                 *store = (char) number;
  557.                 break;
  558.             }
  559.             if ((ctrl = strchr(escmap, *fetch)) != NULL) {
  560.                 *store = escvalue[ctrl - escmap];
  561.                 ++fetch;
  562.                 break;
  563.             }
  564.             /* Literal escapes. */
  565.         default:
  566.             /* Character. */
  567.             *store = *fetch++;
  568.         }
  569.     }
  570.     *store++ = '\0';
  571.     return ((long) (store - buf));
  572. }
  573.  
  574.